extern crate actix_web;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use std::cell::Cell;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

use actix_web::{actix, App, Error, http, HttpRequest, HttpResponse, Responder, server, Path};
use actix_web::dev::Handler;
use actix_web::FromRequest;
use actix_web::http::Method;

fn main() {
//    per_thread_stat();
//    share_thread_stat();
    return_json();
}

fn simple() {
    fn index(_req: &HttpRequest) -> &'static str {
        "Hello world!"
    }

    server::new(|| App::new().resource("/", |r| r.f(index)))
        .bind("127.0.0.1:8088")
        .unwrap()
        .run();
}

fn stat() {
    struct AppState {
        counter: Cell<usize>,
    }
    fn index(req: &HttpRequest<AppState>) -> String {
        let count = req.state().counter.get() + 1; // <- get count
        req.state().counter.set(count); // <- store new count in state

        format!("Request number: {}", count) // <- response with count
    }

    server::new(|| {
        App::with_state(AppState { counter: Cell::new(0) })
            .prefix("/app")
            .resource("/", |r| r.method(http::Method::GET).f(index))
    }).bind("127.0.0.1:8088")
        .unwrap()
        .run()
}

fn per_thread_stat() {
    struct MyHandler(Cell<usize>);

    impl<S> Handler<S> for MyHandler {
        type Result = HttpResponse;

        /// Handle request
        fn handle(&self, req: &HttpRequest<S>) -> Self::Result {
            let i = self.0.get();
            self.0.set(i + 1);
            HttpResponse::Ok().into()
        }
    }

    server::new(|| App::new()
        //use r.h() to bind handler, not the r.f()
        .resource("/", |r| r.h(MyHandler(Cell::new(0)))))
        .bind("127.0.0.1:8088")
        .unwrap()
        .run();
}

fn share_thread_stat() {
    struct MyHandler(Arc<AtomicUsize>);

    impl<S> Handler<S> for MyHandler {
        type Result = HttpResponse;

        /// Handle request
        fn handle(&self, req: &HttpRequest<S>) -> Self::Result {
            self.0.fetch_add(1, Ordering::Relaxed);
            HttpResponse::Ok().into()
        }
    }

    let sys = actix::System::new("example");

    let inc = Arc::new(AtomicUsize::new(0));

    server::new(
        move || {
            let cloned = inc.clone();
            App::new()
                .resource("/", move |r| r.h(MyHandler(cloned)))
        })
        .bind("127.0.0.1:8088").unwrap()
        .start();

    println!("Started http server: 127.0.0.1:8088");
    let _ = sys.run();
}

fn return_json() {
    #[derive(Serialize)]
    struct MyObj {
        name: &'static str,
    }

    /// Responder
    impl Responder for MyObj {
        type Item = HttpResponse;
        type Error = Error;

        fn respond_to<S>(self, req: &HttpRequest<S>) -> Result<HttpResponse, Error> {
            let body = serde_json::to_string(&self)?;

            // Create response and set content type
            Ok(HttpResponse::Ok()
                .content_type("application/json")
                .body(body))
        }
    }

    fn index(req: &HttpRequest) -> impl Responder {
        MyObj { name: "user" }
    }

    fn index1(req: &HttpRequest) -> HttpResponse {
        let params = Path::<(String, String)>::extract(req);
        let info = Json::<MyInfo>::extract(req);
    }


    let sys = actix::System::new("example");

    server::new(
        || App::new()
            .resource("/", |r| r.method(http::Method::GET).f(index))
    )
        .bind("127.0.0.1:8088").unwrap()
        .start();

    println!("Started http server: 127.0.0.1:8088");
    let _ = sys.run();
}